#pragma once
#include "DateBase.hpp"
#include "Frame.pb.h"
#include <boost/asio.hpp>
#include <deque>

namespace MRMDS::Server
{
class Session : public std::enable_shared_from_this<Session>
{
  public:
    using SharePtr = std::shared_ptr<Session>;
    static SharePtr CreatSharePtr(boost::asio::io_context &ioctx, DataBase::SharePtr db)
    {
        return SharePtr(new Session(ioctx, db));
    }

    boost::asio::ip::tcp::socket &Socket() { return socket; }
    void Start();

  private:
    Session(boost::asio::io_context &ioctx, DataBase::SharePtr db) : socket(ioctx), db(db) {}
    int PackBuffer(Message::Frame &frame);
    void OnDataReceived(const boost::system::error_code &error, std::size_t bytes_transferred);
    void OnReceiveFrame(const Message::Frame &frame);
    void OnSendFinished(const boost::system::error_code &error, std::size_t bytes_transferred);
    void StartAsyncSend();
    template <class T> void SendFrame(const T &req_res)
    {
        Message::Frame frame;
        google::protobuf::Any *data = new google::protobuf::Any();
        data->PackFrom(req_res);
        frame.set_allocated_data(data);
        frames.push_back(frame);
        if (isSendFinished)
        {
            StartAsyncSend();
        }
    }
    boost::asio::ip::tcp::socket socket;
    std::array<char, 1024> buf;
    std::array<char, 1024> packBuf;
    DataBase::SharePtr db;
    bool isReadFrame = false;
    bool isSendFinished = true;
    std::deque<Message::Frame> frames;
};
} // namespace MRMDS::Server